package com.absorbx.jcr.test;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;

import javax.jcr.ImportUUIDBehavior;
import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.springmodules.jcr.JcrCallback;
import org.springmodules.jcr.JcrTemplate;

import com.absorbx.jcr.test.annotation.NodeSet;

public class JcrTestExecutionListener extends AbstractTestExecutionListener {

	private final Map<Method, Annotation> configurationCache = Collections
			.synchronizedMap(new IdentityHashMap<Method, Annotation>());

	public void beforeTestMethod(TestContext testContext) throws Exception {
		final NodeSet node = (NodeSet) findAnnotation(testContext
				.getTestMethod(), NodeSet.class);
		if (node != null) {
			JcrTemplate jcrTemplate = (JcrTemplate) testContext
					.getApplicationContext().getBean("jcrTemplate");

			jcrTemplate.execute(new JcrCallback() {

				@Override
				public Object doInJcr(Session session) throws IOException,
						RepositoryException {
					BufferedInputStream bufferedInputStream = new BufferedInputStream(
							new FileInputStream(node.xmlFilePath()));
					session
							.importXML(
									getParentPath(node.path()),
									bufferedInputStream,
									ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
					session.save();
					return null;
				}

			});
		}

	}

	public void afterTestMethod(TestContext testContext) throws Exception {
		final NodeSet node = (NodeSet) findAnnotation(testContext
				.getTestMethod(), NodeSet.class);
		if (node != null) {
			JcrTemplate jcrTemplate = (JcrTemplate) testContext
					.getApplicationContext().getBean("jcrTemplate");
			jcrTemplate.execute(new JcrCallback() {

				@Override
				public Object doInJcr(Session session) throws IOException,
						RepositoryException {
					session.getItem(node.path()).remove();
					session.save();
					return null;
				}

			});
			// jcrTemplate.getItem(node.path()).remove();
			// jcrTemplate.save();
		}
	}

	private Annotation findAnnotation(Method method,
			Class<? extends Annotation> annotationType) {
		if (configurationCache.containsKey(method)) {
			return configurationCache.get(method);
		} else {

			Annotation annotation = AnnotationUtils.findAnnotation(method,
					annotationType);

			configurationCache.put(method, annotation);
			return annotation;

		}
	}

	private String getParentPath(String path) {
		int po = path.lastIndexOf("/");

		if (po == 0) {
			return "/";
		} else {
			return path.substring(0, po);
		}

	}

}
